package com.cskaoyan.service.impl;

import com.cskaoyan.bean.*;
import com.cskaoyan.bean.admin.vo.ExpressConfigDataVO;
import com.cskaoyan.bean.vo.CartCouponVo;
import com.cskaoyan.bean.wx.vo.CartCheckOutBO;
import com.cskaoyan.bean.wx.vo.CartCheckOutVO;
import com.cskaoyan.bean.wx.vo.CartIndexVO;
import com.cskaoyan.mapper.*;
import com.cskaoyan.service.CartService;
import com.cskaoyan.service.SystemService;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.subject.Subject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.lang.System;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.List;

/**
 * @PROJECT_NAME: market_34th
 * @DESCRIPTION:
 * @Author: qiu
 * @DATE: 2021/10/22 10:42
 */
@Service
public class CartServiceImpl implements CartService {

    @Autowired
    CartMapper cartMapper;

    @Autowired
    GoodsMapper goodsMapper;

    @Autowired
    ProductMapper productMapper;

    @Autowired
    SystemService systemService;

    @Autowired
    CouponMapper couponMapper;

    @Autowired
    CouponUserMapper couponUserMapper;

    @Autowired
    AddressMapper addressMapper;

    /**
     * 获取购物车首页
     * @return
     */
    @Override
    public CartIndexVO getIndex() {

        // 获取用户信息
        Subject subject = SecurityUtils.getSubject();
        User user = (User) subject.getPrincipals().getPrimaryPrincipal();
        Integer id = user.getId();

        // 查询用户的购物车所有商品
        CartExample example = new CartExample();
        CartExample.Criteria criteria = example.createCriteria();
        criteria.andUserIdEqualTo(id);  // 当前用户的所有购物车信息

        List<Cart> cartList = cartMapper.selectByExample(example);

        // 统计购物车相关信息
        double checkPriceTotal = 0;  // 已选中商品的结算价格
        double priceTotal = 0;   // 所有商品的结算价格
        Integer checkedGoodsAmount = 0; // 已选中商品的数量总和
        Integer goodsAmount = 0; // 所有商品的数量总和

        for (Cart cart : cartList) {
            double price = cart.getPrice() * cart.getNumber();
            Short nums = cart.getNumber();
            priceTotal += price;    // 统计全局价格
            goodsAmount += nums;    // 统计全局数量

            if(cart.getChecked()){  // 统计已选中的结算价格、数量总和
                checkPriceTotal += price;
                checkedGoodsAmount += nums;
            }
        }

        // 返回数据的封装
        CartIndexVO cartIndexVO = new CartIndexVO();
        CartIndexVO.CartTotalDTO cartTotalDTO = new CartIndexVO.CartTotalDTO();
        cartTotalDTO.setCheckedGoodsAmount((int) checkPriceTotal);
        cartTotalDTO.setGoodsAmount((int) priceTotal);
        cartTotalDTO.setCheckedGoodsCount(checkedGoodsAmount);
        cartTotalDTO.setGoodsCount(goodsAmount);

        cartIndexVO.setCartTotal(cartTotalDTO);
        cartIndexVO.setCartList(cartList);

        return cartIndexVO;
    }

    /**
     * 修改购物车商品数量
     * @param cart
     */
    @Override
    public void update(Cart cart) {
        cartMapper.updateByPrimaryKeySelective(cart);
    }

    /**
     * 选中或取消选中购物车商品
     * 参数要求：userId -> 购物车，productIds -> 唯一商品，ischecked -> 修改状态
     * @param ischecked
     * @param productIds
     */
    @Override
    public CartIndexVO checked(Integer ischecked, List<Integer> productIds) {

        // 获取用户信息
        Subject subject = SecurityUtils.getSubject();
        User user = (User) subject.getPrincipals().getPrimaryPrincipal();
        Integer id = user.getId();

        // 修改当前用户对应购物车对应的商品信息
        CartExample example = new CartExample();
        CartExample.Criteria criteria = example.createCriteria();
        criteria.andUserIdEqualTo(id);  // 当前用户对应的购物车
        criteria.andProductIdIn(productIds);   // 购物车对应的商品

        Cart cart = new Cart();
        if(ischecked == 1){
            cart.setChecked(true);
        } else {
            cart.setChecked(false);
        }

        cartMapper.updateByExampleSelective(cart, example);

        return getIndex();
    }


    /**
     * 加入购物车（如果是购物车已有商品则覆盖，如果不是则新增一条购物车记录）
     * @param cart
     * @return
     */
    @Override
    public int add(Cart cart) {

        // 获取用户信息
        // 应该先判断是否登录，未则显示已登录
        Subject subject = SecurityUtils.getSubject();

        if (subject.getPrincipals() == null){
            return -1;
        }

        User user = (User) subject.getPrincipals().getPrimaryPrincipal();
        Integer id = user.getId();

        // 传入的数据格式：{goodsId: 1181021, number: 3, productId: 265}
        // 1. 首先要判断 当前用户的购物车中有没有该商品，逻辑：userId、产品id 去查购物车商品
        CartExample example = new CartExample();
        CartExample.Criteria criteria = example.createCriteria();
        criteria.andUserIdEqualTo(id);  // 当前用户对应的购物车
        criteria.andProductIdEqualTo(cart.getProductId());   // 购物车对应的商品
        criteria.andGoodsIdEqualTo(cart.getGoodsId());

        List<Cart> res = cartMapper.selectByExample(example);

        // 2. 如果查询的结果有信息，说明当前购物车有这个商品，追加number就行
        if(res.size() > 0){
            CartExample example2 = new CartExample();
            CartExample.Criteria criteria2 = example2.createCriteria();
            criteria2.andIdEqualTo(res.get(0).getId());

            Cart cart2 = new Cart();
            int number = (res.get(0).getNumber() + cart.getNumber());
            cart2.setNumber((short) number);

            cartMapper.updateByExampleSelective(cart2, example2);
        }
        else { // 3. 如果没有查询的结果，create一个购物车记录

            int number = cart.getNumber();

            // 需要goods表的 name、goods_sn，
            Goods goods = goodsMapper.selectByPrimaryKey(cart.getGoodsId());
            String goodsName = goods.getName();
            String goodsSn = goods.getGoodsSn();

            // 以及需要product表的pic_url、specifications、price
            Product product = productMapper.selectByPrimaryKey(cart.getProductId());
            String url = product.getUrl();
            String[] specifications = product.getSpecifications();
            BigDecimal price = product.getPrice();

            // 创建购物车商品
            CartExample example2 = new CartExample();
            CartExample.Criteria criteria2 = example2.createCriteria();
            criteria2.andUserIdEqualTo(id);  // 当前用户对应的购物车
            criteria2.andProductIdEqualTo(cart.getProductId());   // 购物车对应的商品
            criteria2.andGoodsIdEqualTo(cart.getGoodsId());

            Cart cart2 = new Cart();
            cart2.setUserId(id);
            cart2.setGoodsId(cart.getGoodsId());
            cart2.setGoodsSn(String.valueOf(cart.getGoodsId()));
            cart2.setProductId(cart.getProductId());
            cart2.setNumber((short) number);
            cart2.setAddTime(new Date());
            cart2.setUpdateTime(new Date());
            cart2.setGoodsName(goodsName);
            cart2.setPicUrl(url);
            cart2.setGoodsSn(goodsSn);
            cart2.setPrice(price.doubleValue());
            cart2.setSpecifications(specifications);

            cartMapper.insertSelective(cart2);
        }

        // 查询用户的购物车产品数量
        CartExample example2 = new CartExample();
        CartExample.Criteria criteria2 = example.createCriteria();
        criteria2.andUserIdEqualTo(id);  // 当前用户对应的购物车

        List<Cart> cartList = cartMapper.selectByExample(example2);
        int nums = 0;
        for (Cart c : cartList) {
            nums += c.getNumber();
        }

        return nums;
    }


    /**
     * 加入购物车（立即购买生成）
     * @param cart
     * @return
     */
    @Override
    public int fastadd(Cart cart) {

        // 应该先判断是否登录，未则显示已登录
        Subject subject = SecurityUtils.getSubject();
        if (subject.getPrincipals() == null){
            return -1;
        }

        // 获取用户信息
        User user = (User) subject.getPrincipals().getPrimaryPrincipal();
        Integer id = user.getId();

        // fastadd相比于add，不需要考虑叠加问题，都是直接覆盖
        // 1. 首先要判断 当前用户的购物车中有没有该商品，逻辑：userId、产品id 去查购物车商品
        CartExample example = new CartExample();
        CartExample.Criteria criteria = example.createCriteria();
        criteria.andUserIdEqualTo(id);  // 当前用户对应的购物车
        criteria.andProductIdEqualTo(cart.getProductId());   // 购物车对应的商品
        criteria.andGoodsIdEqualTo(cart.getGoodsId());

        List<Cart> res = cartMapper.selectByExample(example);

        // 2. 如果查询的结果有信息，说明当前购物车有这个商品，覆盖number
        Cart cart2 = new Cart();

        if(res.size() > 0){
            CartExample example2 = new CartExample();
            CartExample.Criteria criteria2 = example2.createCriteria();
            criteria2.andIdEqualTo(res.get(0).getId());

            cart2.setNumber(cart.getNumber());

            cartMapper.updateByExampleSelective(cart2, example2);

            System.out.println(res.get(0).getId());

            return res.get(0).getId();
        }
        else { // 3. 如果没有查询的结果，create一个购物车记录

            // 需要goods表的 name、goods_sn，
            Goods goods = goodsMapper.selectByPrimaryKey(cart.getGoodsId());
            String goodsName = goods.getName();
            String goodsSn = goods.getGoodsSn();

            // 以及需要product表的pic_url、specifications、price
            Product product = productMapper.selectByPrimaryKey(cart.getProductId());
            String url = product.getUrl();
            String[] specifications = product.getSpecifications();
            BigDecimal price = product.getPrice();

            // 创建购物车商品
            CartExample example2 = new CartExample();
            CartExample.Criteria criteria2 = example2.createCriteria();
            criteria2.andUserIdEqualTo(id);  // 当前用户对应的购物车
            criteria2.andProductIdEqualTo(cart.getProductId());   // 购物车对应的商品
            criteria2.andGoodsIdEqualTo(cart.getGoodsId());

            cart2.setUserId(id);
            cart2.setGoodsId(cart.getGoodsId());
            cart2.setGoodsSn(String.valueOf(cart.getGoodsId()));
            cart2.setProductId(cart.getProductId());
            cart2.setNumber(cart.getNumber());
            cart2.setAddTime(new Date());
            cart2.setUpdateTime(new Date());
            cart2.setGoodsName(goodsName);
            cart2.setPicUrl(url);
            cart2.setGoodsSn(goodsSn);
            cart2.setPrice(price.doubleValue());
            cart2.setSpecifications(specifications);

            cartMapper.insertSelective(cart2);

            return cart2.getId();
        }

    }


    /**
     * 订单确认页面
     * @param bo
     * @return
     */
    @Override
    public CartCheckOutVO checkout(CartCheckOutBO bo) {

        // 入参解析
        Integer cartId = bo.getCartId();    // 立即购买触发：如果是单个产品，就是该产品对应的cartId；如果是多个产品，就是0；如果是购物车中，无论怎样都是0
        Integer addressId = bo.getAddressId();  // 可以获取到地址对象
        Integer couponId = bo.getCouponId();    // id如果是0，就是不使用优惠券；如果大于0，就是使用某个优惠券
        Integer grouponRulesId = bo.getGrouponRulesId();    // 固定是0
        Integer userCouponId = bo.getUserCouponId();    // 用户和优惠券的中间表 userCouponId

        // 获取用户信息
        Subject subject = SecurityUtils.getSubject();
        User user = (User) subject.getPrincipals().getPrimaryPrincipal();
        Integer userId = user.getId();

        // 1.先判断结算的是单个产品，还是多个产品；然后计算出初步的产品总价格
        double goodsTotalPrice = 0; // 商品总价格
        List<Cart> checkedGoodsList = new ArrayList<>(); // 结算清单（userId获得已选中商品）
        Cart cart = new Cart(); // 立即购买情况下查出来的购物车产品
        if(cartId == 0){    // 购物车下单
            // 如果是多个产品，获得已选中的商品清单
            CartExample example = new CartExample();
            CartExample.Criteria criteria = example.createCriteria();
            criteria.andUserIdEqualTo(userId);  // 当前用户对应的购物车
            criteria.andCheckedEqualTo(true);    // 已选中的商品

            checkedGoodsList = cartMapper.selectByExample(example);

            for (Cart c : checkedGoodsList) {
                double price = c.getPrice() * c.getNumber();
                goodsTotalPrice += price;
            }

        } else {    // 立即购买下单
            cart = cartMapper.selectByPrimaryKey(cartId);
            double price = cart.getPrice() * cart.getNumber();
            goodsTotalPrice += price;
        }


        // 2.判断是否需要运费，计算出不使用优惠券的结算价格
        Integer freightPrice = 0;
        ExpressConfigDataVO expressConfigDataVO = systemService.queryExpressConfig();
        String freight_min = expressConfigDataVO.getMarket_express_freight_min();
        String freight_value = expressConfigDataVO.getMarket_express_freight_value();

        if(goodsTotalPrice < Double.parseDouble(freight_min)){
            freightPrice = Integer.parseInt(freight_value);
            goodsTotalPrice += Double.parseDouble(freight_value);
        }

        // 3.统计有几张优惠券能用
        CouponUserExample couponUserExample = new CouponUserExample();
        CouponUserExample.Criteria criteria = couponUserExample.createCriteria();
        criteria.andUserIdEqualTo(userId);
        Integer availableCouponLength = couponUserMapper.selectByExample(couponUserExample).size();

        if(checkedGoodsList.size() == 0){
             checkedGoodsList.add(cart);
        }
        //遍历根据购物车中的商品查询优惠卷
        //查询用户目前还能用的优惠劵
        List<Coupon> coupons = couponMapper.selectCouponJoinCouponUser(userId, 0);
        List<CartCouponVo> couponsToUseList = new ArrayList<>();
        if (coupons != null && coupons.size() > 0) {
            //遍历优惠卷查看可以用于的商品
            for (Coupon coupon : coupons) {
                //转为集合提高效率
                List<Integer> goodsIdList = new ArrayList<>();
                Integer[] goodsValue = coupon.getGoodsValue();
                if (goodsValue != null && goodsValue.length > 0) {
                    goodsIdList = Arrays.asList(goodsValue);
                }

                //计算购物车中的可以用该优惠卷所有商品总价
                double couldBeUsedCouponGoodsTotal = 0;
                //记录购物车id
                int cId = 0;
                int couldBeUserd = 0;
                //遍历购物车查看可以用于该商品的所有商品，长度为0说明是全场优惠卷
                for (Cart c : checkedGoodsList) {
                    if (goodsIdList.contains(c.getGoodsId()) || goodsIdList.size() == 0) {
                        //可以该优惠卷商品总价相加
                        couldBeUsedCouponGoodsTotal += c.getPrice() * c.getNumber();
                        couldBeUserd++;
                    }
                    if (cartId == 0) {
                        cId = c.getId();
                    }
                }

                //如果couldBeUsed>0说明可以使用，具体是否满足金额的
                if (couldBeUserd > 0) {
                    //如果商品总额大于优惠卷总额则添加优惠卷记录为true否则为false
                    CartCouponVo cartCouponVo = new CartCouponVo();
                    cartCouponVo.setId(cId);
                    cartCouponVo.setCid(coupon.getId());
                    cartCouponVo.setName(coupon.getName());
                    cartCouponVo.setDesc(coupon.getDesc());
                    cartCouponVo.setTag(coupon.getTag());
                    if (coupon.getMin() != null) {
                        cartCouponVo.setMin(coupon.getMin().intValue());
                    }
                    if(coupon.getDiscount()!=null){
                        cartCouponVo.setDiscount(coupon.getDiscount().doubleValue());
                    }
                    cartCouponVo.setStartTime(coupon.getStartTime());
                    cartCouponVo.setEndTime(coupon.getEndTime());
                    cartCouponVo.setAvailable(false);

                    //商品总金额大于优惠卷金额说明可以用
                    if (couldBeUsedCouponGoodsTotal >= coupon.getMin().doubleValue()) {
                        cartCouponVo.setAvailable(true);
                        couponsToUseList.add(cartCouponVo);
                    }

                }
            }

            //如果可用的优惠卷不为null则传递回去
            if (couponsToUseList != null && couponsToUseList.size() > 0) {
                availableCouponLength = couponsToUseList.size();
            } else {
                availableCouponLength = 0;
            }

        }


        // 4.判断是否用了优惠券，并计算出最终结算的实际价格
        double actualPrice = 0;
        double orderTotalPrice = 0;
        Integer couponPrice = 0;
        if (couponId > 0){
            Coupon coupon = couponMapper.selectByPrimaryKey(couponId);

            if(coupon == null){ // 这是前端的问题，每次传入couponId都是用户上一次选择的优惠券id
                actualPrice = goodsTotalPrice;
                orderTotalPrice = goodsTotalPrice;
                couponId = -1;
                userCouponId = -1;
            }   else {
                couponPrice = (int) (coupon.getDiscount().doubleValue());
                actualPrice = goodsTotalPrice - couponPrice;
                orderTotalPrice = actualPrice;
            }

        } else {
            actualPrice = goodsTotalPrice;
            orderTotalPrice = goodsTotalPrice;
            couponId = -1;
            userCouponId = -1;
        }

        // 5.获取收获地址信息
        Address checkedAddress = addressMapper.selectByPrimaryKey(addressId);

        // 数据的封装
        CartCheckOutVO vo = new CartCheckOutVO();
        vo.setGrouponRulesId(0);
        vo.setGrouponPrice(0);
        vo.setCartId(cartId);
        vo.setUserCouponId(userCouponId);
        vo.setCouponId(couponId);
        vo.setAddressId(addressId);
        vo.setFreightPrice(freightPrice);
        vo.setGoodsTotalPrice((int) goodsTotalPrice);
        vo.setCouponPrice(couponPrice);
        vo.setAvailableCouponLength(availableCouponLength);
        vo.setActualPrice((int) actualPrice);
        vo.setOrderTotalPrice((int) orderTotalPrice);
        vo.setCheckedAddress(checkedAddress);
        vo.setCheckedGoodsList(checkedGoodsList);

        return vo;
    }


    /**
     * 统计购物车中产品总数量
     * @return
     */
    @Override
    public Integer goodscount() {

        // 获取用户信息
        Subject subject = SecurityUtils.getSubject();
        PrincipalCollection principals = subject.getPrincipals();
        if (principals == null){
            return 0;
        }
        User user = (User) subject.getPrincipals().getPrimaryPrincipal();
        Integer id = user.getId();

        CartExample example = new CartExample();
        CartExample.Criteria criteria = example.createCriteria();
        criteria.andUserIdEqualTo(id);  // 当前用户对应的购物车

        List<Cart> carts = cartMapper.selectByExample(example);
        int numbers = 0;
        for (Cart cart : carts) {
            numbers += cart.getNumber();
        }

        return numbers;
    }


    /**
     * 删除购物车产品，返回删除后的购物车信息
     * @param productIds
     * @return
     */
    @Override
    public CartIndexVO delete(List<Integer> productIds) {

        // 获取用户信息（也可以先判断是否登录）
        Subject subject = SecurityUtils.getSubject();
        User user = (User) subject.getPrincipals().getPrimaryPrincipal();
        Integer id = user.getId();

        CartExample example = new CartExample();
        CartExample.Criteria criteria = example.createCriteria();
        criteria.andUserIdEqualTo(id);  // 当前用户对应的购物车
        criteria.andProductIdIn(productIds);

        cartMapper.deleteByExample(example);

        return getIndex();
    }
}